home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / gawk-3.000 / gawk-3 / gawk-3.0.0 / builtin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-09  |  34.3 KB  |  1,598 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26.  
  27. #include "awk.h"
  28. #undef HUGE
  29. #undef CHARBITS
  30. #undef INTBITS
  31. #include <math.h>
  32.  
  33. #ifndef HAVE_RANDOM
  34. extern char *initstate P((unsigned seed, char *state, int n));
  35. extern char *setstate P((char *state));
  36. extern long random P((void));
  37. #define SRANDOM_PROTO
  38. #endif
  39. #ifdef SRANDOM_PROTO
  40. extern void srandom P((unsigned int seed));
  41. #endif
  42.  
  43. extern NODE **fields_arr;
  44. extern int output_is_tty;
  45.  
  46. static NODE *sub_common P((NODE *tree, int how_many, int backdigs));
  47. NODE *format_tree P((const char *, int, NODE *));
  48.  
  49. #ifdef _CRAY
  50. /* Work around a problem in conversion of doubles to exact integers. */
  51. #include <float.h>
  52. #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
  53. #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
  54.  
  55. /* Force the standard C compiler to use the library math functions. */
  56. extern double exp(double);
  57. double (*Exp)() = exp;
  58. #define exp(x) (*Exp)(x)
  59. extern double log(double);
  60. double (*Log)() = log;
  61. #define log(x) (*Log)(x)
  62. #else
  63. #define Floor(n) floor(n)
  64. #define Ceil(n) ceil(n)
  65. #endif
  66.  
  67. #define DEFAULT_G_PRECISION 6
  68.  
  69. #ifdef GFMT_WORKAROUND
  70. /* semi-temporary hack, mostly to gracefully handle VMS */
  71. static void sgfmt P((char *buf, const char *format, int alt,
  72.              int fwidth, int precision, double value));
  73. #endif /* GFMT_WORKAROUND */
  74.  
  75. /*
  76.  * On the alpha, LONG_MAX is too big for doing rand().
  77.  * On the Cray (Y-MP, anyway), ints and longs are 64 bits, but
  78.  * random() does things in terms of 32 bits. So we have to chop
  79.  * LONG_MAX down.
  80.  * On SGI with 64 bit support (IRIX 6.*), check the size of _MIPS_SZLONG 
  81.  * and chop.... Per limits.h. 
  82.  */
  83. #if (defined(__alpha) && defined(__osf__)) || defined(_CRAY) || (_MIPS_SZLONG == 64)
  84. #define GAWK_RANDOM_MAX (LONG_MAX & 0x7fffffff)
  85. #else
  86. #define GAWK_RANDOM_MAX LONG_MAX
  87. #endif
  88.  
  89. static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp,
  90.                const char *from, struct redirect *rp, int flush));
  91.  
  92. /* efwrite --- like fwrite, but with error checking */
  93.  
  94. static void
  95. efwrite(ptr, size, count, fp, from, rp, flush)
  96. const void *ptr;
  97. size_t size, count;
  98. FILE *fp;
  99. const char *from;
  100. struct redirect *rp;
  101. int flush;
  102. {
  103.     errno = 0;
  104.     if (fwrite(ptr, size, count, fp) != count)
  105.         goto wrerror;
  106.     if (flush
  107.       && ((fp == stdout && output_is_tty)
  108.        || (rp && (rp->flag & RED_NOBUF)))) {
  109.         fflush(fp);
  110.         if (ferror(fp))
  111.             goto wrerror;
  112.     }
  113.     return;
  114.  
  115. wrerror:
  116.     fatal("%s to \"%s\" failed (%s)", from,
  117.         rp ? rp->value : "standard output",
  118.         errno ? strerror(errno) : "reason unknown");
  119. }
  120.  
  121. /* do_exp --- exponential function */
  122.  
  123. NODE *
  124. do_exp(tree)
  125. NODE *tree;
  126. {
  127.     NODE *tmp;
  128.     double d, res;
  129.  
  130.     tmp = tree_eval(tree->lnode);
  131.     d = force_number(tmp);
  132.     free_temp(tmp);
  133.     errno = 0;
  134.     res = exp(d);
  135.     if (errno == ERANGE)
  136.         warning("exp argument %g is out of range", d);
  137.     return tmp_number((AWKNUM) res);
  138. }
  139.  
  140. /* stdfile --- return fp for a standard file */
  141.  
  142. /*
  143.  * This function allows `fflush("/dev/stdout")' to work.
  144.  * The other files will be available via getredirect().
  145.  * /dev/stdin is not included, since fflush is only for output.
  146.  */
  147.  
  148. static FILE *
  149. stdfile(name, len)
  150. char *name;
  151. size_t len;
  152. {
  153.     if (len == 11) {
  154.         if (STREQN(name, "/dev/stderr", 11))
  155.             return stderr;
  156.         else if (STREQN(name, "/dev/stdout", 11))
  157.             return stdout;
  158.     }
  159.  
  160.     return NULL;
  161. }
  162.  
  163. /* do_fflush --- flush output, either named file or pipe or everything */
  164.  
  165. NODE *
  166. do_fflush(tree)
  167. NODE *tree;
  168. {
  169.     extern struct redirect *getredirect();
  170.     struct redirect *rp;
  171.     NODE *tmp;
  172.     FILE *fp;
  173.     int status = 0;
  174.     char *file;
  175.  
  176.     /* fflush() --- flush stdout */
  177.     if (tree == NULL) {
  178.         status = fflush(stdout);
  179.         return tmp_number((AWKNUM) status);
  180.     }
  181.  
  182.     tmp = tree_eval(tree->lnode);
  183.     tmp = force_string(tmp);
  184.     file = tmp->stptr;
  185.  
  186.     /* fflush("") --- flush all */
  187.     if (tmp->stlen == 0) {
  188.         status = flush_io();
  189.         free_temp(tmp);
  190.         return tmp_number((AWKNUM) status);
  191.     }
  192.  
  193.     rp = getredirect(tmp->stptr, tmp->stlen);
  194.     status = 1;
  195.     if (rp != NULL) {
  196.         if ((rp->flag & (RED_WRITE|RED_APPEND)) == 0) {
  197.             /* if (do_lint) */
  198.                 warning(
  199.         "fflush: cannot flush: %s `%s' opened for reading, not writing",
  200.                 (rp->flag & RED_PIPE) ? "pipe" : "file",
  201.                 file);
  202.             free_temp(tmp);
  203.             return tmp_number((AWKNUM) status);
  204.         }
  205.         fp = rp->fp;
  206.         if (fp != NULL)
  207.             status = fflush(fp);
  208.     } else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) {
  209.         status = fflush(fp);
  210.     } else
  211.         warning("fflush: `%s' is not an open file or pipe", file);
  212.     free_temp(tmp);
  213.     return tmp_number((AWKNUM) status);
  214. }
  215.  
  216. /* do_index --- find index of a string */
  217.  
  218. NODE *
  219. do_index(tree)
  220. NODE *tree;
  221. {
  222.     NODE *s1, *s2;
  223.     register char *p1, *p2;
  224.     register size_t l1, l2;
  225.     long ret;
  226.  
  227.  
  228.     s1 = tree_eval(tree->lnode);
  229.     s2 = tree_eval(tree->rnode->lnode);
  230.     force_string(s1);
  231.     force_string(s2);
  232.     p1 = s1->stptr;
  233.     p2 = s2->stptr;
  234.     l1 = s1->stlen;
  235.     l2 = s2->stlen;
  236.     ret = 0;
  237.  
  238.     /* IGNORECASE will already be false if posix */
  239.     if (IGNORECASE) {
  240.         while (l1 > 0) {
  241.             if (l2 > l1)
  242.                 break;
  243.             if (casetable[(int)*p1] == casetable[(int)*p2]
  244.                 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
  245.                 ret = 1 + s1->stlen - l1;
  246.                 break;
  247.             }
  248.             l1--;
  249.             p1++;
  250.         }
  251.     } else {
  252.         while (l1 > 0) {
  253.             if (l2 > l1)
  254.                 break;
  255.             if (*p1 == *p2
  256.                 && (l2 == 1 || STREQN(p1, p2, l2))) {
  257.                 ret = 1 + s1->stlen - l1;
  258.                 break;
  259.             }
  260.             l1--;
  261.             p1++;
  262.         }
  263.     }
  264.     free_temp(s1);
  265.     free_temp(s2);
  266.     return tmp_number((AWKNUM) ret);
  267. }
  268.  
  269. /* double_to_int --- convert double to int, used several places */
  270.  
  271. double
  272. double_to_int(d)
  273. double d;
  274. {
  275.     if (d >= 0)
  276.         d = Floor(d);
  277.     else
  278.         d = Ceil(d);
  279.     return d;
  280. }
  281.  
  282. /* do_int --- convert double to int for awk */
  283.  
  284. NODE *
  285. do_int(tree)
  286. NODE *tree;
  287. {
  288.     NODE *tmp;
  289.     double d;
  290.  
  291.     tmp = tree_eval(tree->lnode);
  292.     d = force_number(tmp);
  293.     d = double_to_int(d);
  294.     free_temp(tmp);
  295.     return tmp_number((AWKNUM) d);
  296. }
  297.  
  298. /* do_length --- length of a string or $0 */
  299.  
  300. NODE *
  301. do_length(tree)
  302. NODE *tree;
  303. {
  304.     NODE *tmp;
  305.     size_t len;
  306.  
  307.     tmp = tree_eval(tree->lnode);
  308.     len = force_string(tmp)->stlen;
  309.     free_temp(tmp);
  310.     return tmp_number((AWKNUM) len);
  311. }
  312.  
  313. /* do_log --- the log function */
  314.  
  315. NODE *
  316. do_log(tree)
  317. NODE *tree;
  318. {
  319.     NODE *tmp;
  320.     double d, arg;
  321.  
  322.     tmp = tree_eval(tree->lnode);
  323.     arg = (double) force_number(tmp);
  324.     if (arg < 0.0)
  325.         warning("log called with negative argument %g", arg);
  326.     d = log(arg);
  327.     free_temp(tmp);
  328.     return tmp_number((AWKNUM) d);
  329. }
  330.  
  331. /*
  332.  * format_tree() formats nodes of a tree, starting with a left node,
  333.  * and accordingly to a fmt_string providing a format like in
  334.  * printf family from C library.  Returns a string node which value
  335.  * is a formatted string.  Called by  sprintf function.
  336.  *
  337.  * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
  338.  * for taming this beast and making it compatible with ANSI C.
  339.  */
  340.  
  341. NODE *
  342. format_tree(fmt_string, n0, carg)
  343. const char *fmt_string;
  344. int n0;
  345. register NODE *carg;
  346. {
  347. /* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
  348. /* difference of pointers should be of ptrdiff_t type, but let us be kind */
  349. #define bchunk(s, l) if (l) { \
  350.     while ((l) > ofre) { \
  351.         long olen = obufout - obuf; \
  352.         erealloc(obuf, char *, osiz * 2, "format_tree"); \
  353.         ofre += osiz; \
  354.         osiz *= 2; \
  355.         obufout = obuf + olen; \
  356.     } \
  357.     memcpy(obufout, s, (size_t) (l)); \
  358.     obufout += (l); \
  359.     ofre -= (l); \
  360. }
  361.  
  362. /* copy one byte from 's' to 'obufout' checking for space in the process */
  363. #define bchunk_one(s) { \
  364.     if (ofre <= 0) { \
  365.         long olen = obufout - obuf; \
  366.         erealloc(obuf, char *, osiz * 2, "format_tree"); \
  367.         ofre += osiz; \
  368.         osiz *= 2; \
  369.         obufout = obuf + olen; \
  370.     } \
  371.     *obufout++ = *s; \
  372.     --ofre; \
  373. }
  374.  
  375. /* Is there space for something L big in the buffer? */
  376. #define chksize(l)  if ((l) > ofre) { \
  377.     long olen = obufout - obuf; \
  378.     erealloc(obuf, char *, osiz * 2, "format_tree"); \
  379.     obufout = obuf + olen; \
  380.     ofre += osiz; \
  381.     osiz *= 2; \
  382. }
  383.  
  384. /*
  385.  * Get the next arg to be formatted.  If we've run out of args,
  386.  * return "" (Null string) 
  387.  */
  388. #define parse_next_arg() { \
  389.     if (carg == NULL) { \
  390.         toofew = TRUE; \
  391.         break; \
  392.     } else { \
  393.         arg = tree_eval(carg->lnode); \
  394.         carg = carg->rnode; \
  395.     } \
  396. }
  397.  
  398.     NODE *r;
  399.     int toofew = FALSE;
  400.     char *obuf, *obufout;
  401.     size_t osiz, ofre;
  402.     char *chbuf;
  403.     const char *s0, *s1;
  404.     int cs1;
  405.     NODE *arg;
  406.     long fw, prec;
  407.     int lj, alt, big, bigbig, small, have_prec, need_format;
  408.     long *cur = NULL;
  409.     long val;
  410. #ifdef sun386        /* Can't cast unsigned (int/long) from ptr->value */
  411.     long tmp_uval;    /* on 386i 4.0.1 C compiler -- it just hangs */
  412. #endif
  413.     unsigned long uval;
  414.     int sgn;
  415.     int base = 0;
  416.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  417.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  418.     char *cp;
  419.     char *fill;
  420.     double tmpval;
  421.     char signchar = FALSE;
  422.     size_t len;
  423.     static char sp[] = " ";
  424.     static char zero_string[] = "0";
  425.     static char lchbuf[] = "0123456789abcdef";
  426.     static char Uchbuf[] = "0123456789ABCDEF";
  427.  
  428.     emalloc(obuf, char *, 120, "format_tree");
  429.     obufout = obuf;
  430.     osiz = 120;
  431.     ofre = osiz - 1;
  432.  
  433.     need_format = FALSE;
  434.  
  435.     s0 = s1 = fmt_string;
  436.     while (n0-- > 0) {
  437.         if (*s1 != '%') {
  438.             s1++;
  439.             continue;
  440.         }
  441.         need_format = TRUE;
  442.         bchunk(s0, s1 - s0);
  443.         s0 = s1;
  444.         cur = &fw;
  445.         fw = 0;
  446.         prec = 0;
  447.         have_prec = FALSE;
  448.         signchar = FALSE;
  449.         lj = alt = big = bigbig = small = FALSE;
  450.         fill = sp;
  451.         cp = cend;
  452.         chbuf = lchbuf;
  453.         s1++;
  454.  
  455. retry:
  456.         if (n0-- <= 0)    /* ran out early! */
  457.             break;
  458.  
  459.         switch (cs1 = *s1++) {
  460.         case (-1):    /* dummy case to allow for checking */
  461. check_pos:
  462.             if (cur != &fw)
  463.                 break;        /* reject as a valid format */
  464.             goto retry;
  465.         case '%':
  466.             need_format = FALSE;
  467.             bchunk_one("%");
  468.             s0 = s1;
  469.             break;
  470.  
  471.         case '0':
  472.             if (lj)
  473.                 goto retry;
  474.             if (cur == &fw)
  475.                 fill = zero_string;
  476.             /* FALL through */
  477.         case '1':
  478.         case '2':
  479.         case '3':
  480.         case '4':
  481.         case '5':
  482.         case '6':
  483.         case '7':
  484.         case '8':
  485.         case '9':
  486.             if (cur == NULL)
  487.                 break;
  488.             if (prec >= 0)
  489.                 *cur = cs1 - '0';
  490.             /*
  491.              * with a negative precision *cur is already set
  492.              * to -1, so it will remain negative, but we have
  493.              * to "eat" precision digits in any case
  494.              */
  495.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  496.                 --n0;
  497.                 *cur = *cur * 10 + *s1++ - '0';
  498.             }
  499.             if (prec < 0)     /* negative precision is discarded */
  500.                 have_prec = FALSE;
  501.             if (cur == &prec)
  502.                 cur = NULL;
  503.             if (n0 == 0)    /* badly formatted control string */
  504.                 continue;
  505.             goto retry;
  506.         case '*':
  507.             if (cur == NULL)
  508.                 break;
  509.             parse_next_arg();
  510.             *cur = force_number(arg);
  511.             free_temp(arg);
  512.             if (cur == &prec)
  513.                 cur = NULL;
  514.             goto retry;
  515.         case ' ':        /* print ' ' or '-' */
  516.                     /* 'space' flag is ignored */
  517.                     /* if '+' already present  */
  518.             if (signchar != FALSE) 
  519.                 goto check_pos;
  520.             /* FALL THROUGH */
  521.         case '+':        /* print '+' or '-' */
  522.             signchar = cs1;
  523.             goto check_pos;
  524.         case '-':
  525.             if (prec < 0)
  526.                 break;
  527.             if (cur == &prec) {
  528.                 prec = -1;
  529.                 goto retry;
  530.             }
  531.             fill = sp;      /* if left justified then other */
  532.             lj++;         /* filling is ignored */
  533.             goto check_pos;
  534.         case '.':
  535.             if (cur != &fw)
  536.                 break;
  537.             cur = ≺
  538.             have_prec = TRUE;
  539.             goto retry;
  540.         case '#':
  541.             alt = TRUE;
  542.             goto check_pos;
  543.         case 'l':
  544.             if (big)
  545.                 break;
  546.             else {
  547.                 static int warned = FALSE;
  548.                 
  549.                 if (do_lint && ! warned) {
  550.                     warning("`l' is meaningless in awk formats; ignored");
  551.                     warned = TRUE;
  552.                 }
  553.                 if (do_posix)
  554.                     fatal("'l' is not permitted in POSIX awk formats");
  555.             }
  556.             big = TRUE;
  557.             goto retry;
  558.         case 'L':
  559.             if (bigbig)
  560.                 break;
  561.             else {
  562.                 static int warned = FALSE;
  563.                 
  564.                 if (do_lint && ! warned) {
  565.                     warning("`L' is meaningless in awk formats; ignored");
  566.                     warned = TRUE;
  567.                 }
  568.                 if (do_posix)
  569.                     fatal("'L' is not permitted in POSIX awk formats");
  570.             }
  571.             bigbig = TRUE;
  572.             goto retry;
  573.         case 'h':
  574.             if (small)
  575.                 break;
  576.             else {
  577.                 static int warned = FALSE;
  578.                 
  579.                 if (do_lint && ! warned) {
  580.                     warning("`h' is meaningless in awk formats; ignored");
  581.                     warned = TRUE;
  582.                 }
  583.                 if (do_posix)
  584.                     fatal("'h' is not permitted in POSIX awk formats");
  585.             }
  586.             small = TRUE;
  587.             goto retry;
  588.         case 'c':
  589.             need_format = FALSE;
  590.             parse_next_arg();
  591.             if (arg->flags & NUMBER) {
  592. #ifdef sun386
  593.                 tmp_uval = arg->numbr; 
  594.                 uval = (unsigned long) tmp_uval;
  595. #else
  596.                 uval = (unsigned long) arg->numbr;
  597. #endif
  598.                 cpbuf[0] = uval;
  599.                 prec = 1;
  600.                 cp = cpbuf;
  601.                 goto pr_tail;
  602.             }
  603.             if (have_prec == FALSE)
  604.                 prec = 1;
  605.             else if (prec > arg->stlen)
  606.                 prec = arg->stlen;
  607.             cp = arg->stptr;
  608.             goto pr_tail;
  609.         case 's':
  610.             need_format = FALSE;
  611.             parse_next_arg();
  612.             arg = force_string(arg);
  613.             if (! have_prec || prec > arg->stlen)
  614.                 prec = arg->stlen;
  615.             cp = arg->stptr;
  616.             goto pr_tail;
  617.         case 'd':
  618.         case 'i':
  619.             need_format = FALSE;
  620.             parse_next_arg();
  621.             tmpval = force_number(arg);
  622.             /* this ugly cast fixes a (sunos) pcc problem. sigh. */
  623.             if (tmpval > (double) ((unsigned long) ULONG_MAX)
  624.                || tmpval < LONG_MIN) {
  625.                 /* out of range - emergency use of %g format */
  626.                 cs1 = 'g';
  627.                 goto format_float;
  628.             }
  629.             val = (long) tmpval;
  630.  
  631.             if (val < 0) {
  632.                 sgn = TRUE;
  633.                 if (val > LONG_MIN)
  634.                     uval = (unsigned long) -val;
  635.                 else
  636.                     uval = (unsigned long) (-(LONG_MIN + 1))
  637.                            + (unsigned long) 1;
  638.             } else {
  639.                 sgn = FALSE;
  640.                 uval = (unsigned long) val;
  641.             }
  642.             do {
  643.                 *--cp = (char) ('0' + uval % 10);
  644.                 uval /= 10;
  645.             } while (uval > 0);
  646.             if (sgn)
  647.                 *--cp = '-';
  648.             else if (signchar)
  649.                 *--cp = signchar;
  650.             /*
  651.              * precision overrides '0' flags. however, for
  652.              * integer formats, precsion is minimum number of
  653.              * *digits*, not characters, thus we want to fill
  654.              * with zeroes.
  655.              */
  656.             if (have_prec)
  657.                 fill = zero_string;
  658.             if (prec > fw)
  659.                 fw = prec;
  660.             prec = cend - cp;
  661.             if (fw > prec && ! lj && fill != sp
  662.                 && (*cp == '-' || signchar)) {
  663.                 bchunk_one(cp);
  664.                 cp++;
  665.                 prec--;
  666.                 fw--;
  667.             }
  668.             goto pr_tail;
  669.         case 'X':
  670.             chbuf = Uchbuf;    /* FALL THROUGH */
  671.         case 'x':
  672.             base += 6;    /* FALL THROUGH */
  673.         case 'u':
  674.             base += 2;    /* FALL THROUGH */
  675.         case 'o':
  676.             base += 8;
  677.             need_format = FALSE;
  678.             parse_next_arg();
  679.             tmpval = force_number(arg);
  680.             /* this ugly cast fixes a (sunos) pcc problem. sigh. */
  681.             if (tmpval > (double) ((unsigned long) ULONG_MAX)
  682.                || tmpval < LONG_MIN) {
  683.                 /* out of range - emergency use of %g format */
  684.                 cs1 = 'g';
  685.                 goto format_float;
  686.             }
  687.             uval = (unsigned long) tmpval;
  688.             /*
  689.              * precision overrides '0' flags. however, for
  690.              * integer formats, precsion is minimum number of
  691.              * *digits*, not characters, thus we want to fill
  692.              * with zeroes.
  693.              */
  694.             if (have_prec)
  695.                 fill = zero_string;
  696.             do {
  697.                 *--cp = chbuf[uval % base];
  698.                 uval /= base;
  699.             } while (uval > 0);
  700.             if (alt) {
  701.                 if (base == 16) {
  702.                     *--cp = cs1;
  703.                     *--cp = '0';
  704.                     if (fill != sp) {
  705.                         bchunk(cp, 2);
  706.                         cp += 2;
  707.                         fw -= 2;
  708.                     }
  709.                 } else if (base == 8)
  710.                     *--cp = '0';
  711.             }
  712.             base = 0;
  713.             if (prec > fw)
  714.                 fw = prec;
  715.             prec = cend - cp;
  716.     pr_tail:
  717.             if (! lj) {
  718.                 while (fw > prec) {
  719.                         bchunk_one(fill);
  720.                     fw--;
  721.                 }
  722.             }
  723.             bchunk(cp, (int) prec);
  724.             while (fw > prec) {
  725.                 bchunk_one(fill);
  726.                 fw--;
  727.             }
  728.             s0 = s1;
  729.             free_temp(arg);
  730.             break;
  731.         case 'g':
  732.         case 'G':
  733.         case 'e':
  734.         case 'f':
  735.         case 'E':
  736.             need_format = FALSE;
  737.             parse_next_arg();
  738.             tmpval = force_number(arg);
  739.      format_float:
  740.             free_temp(arg);
  741.             if (! have_prec)
  742.                 prec = DEFAULT_G_PRECISION;
  743.             chksize(fw + prec + 9);    /* 9 == slop */
  744.  
  745.             cp = cpbuf;
  746.             *cp++ = '%';
  747.             if (lj)
  748.                 *cp++ = '-';
  749.             if (signchar)
  750.                 *cp++ = signchar;
  751.             if (alt)
  752.                 *cp++ = '#';
  753.             if (fill != sp)
  754.                 *cp++ = '0';
  755.             cp = strcpy(cp, "*.*") + 3;
  756.             *cp++ = cs1;
  757.             *cp = '\0';
  758. #ifndef GFMT_WORKAROUND
  759.             (void) sprintf(obufout, cpbuf,
  760.                        (int) fw, (int) prec, (double) tmpval);
  761. #else    /* GFMT_WORKAROUND */
  762.             if (cs1 == 'g' || cs1 == 'G')
  763.                 sgfmt(obufout, cpbuf, (int) alt,
  764.                        (int) fw, (int) prec, (double) tmpval);
  765.             else
  766.                 (void) sprintf(obufout, cpbuf,
  767.                        (int) fw, (int) prec, (double) tmpval);
  768. #endif    /* GFMT_WORKAROUND */
  769.             len = strlen(obufout);
  770.             ofre -= len;
  771.             obufout += len;
  772.             s0 = s1;
  773.             break;
  774.         default:
  775.             break;
  776.         }
  777.         if (toofew)
  778.             fatal("%s\n\t`%s'\n\t%*s%s",
  779.             "not enough arguments to satisfy format string",
  780.             fmt_string, s1 - fmt_string - 2, "",
  781.             "^ ran out for this one"
  782.             );
  783.     }
  784.     if (do_lint) {
  785.         if (need_format)
  786.             warning(
  787.             "printf format specifier does not have control letter");
  788.         if (carg != NULL)
  789.             warning(
  790.             "too many arguments supplied for format string");
  791.     }
  792.     bchunk(s0, s1 - s0);
  793.     r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
  794.     r->flags |= TEMP;
  795.     return r;
  796. }
  797.  
  798. /* do_sprintf --- perform sprintf */
  799.  
  800. NODE *
  801. do_sprintf(tree)
  802. NODE *tree;
  803. {
  804.     NODE *r;
  805.     NODE *sfmt = force_string(tree_eval(tree->lnode));
  806.  
  807.     r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode);
  808.     free_temp(sfmt);
  809.     return r;
  810. }
  811.  
  812. /* do_printf --- perform printf, including redirection */
  813.  
  814. void
  815. do_printf(tree)
  816. register NODE *tree;
  817. {
  818.     struct redirect *rp = NULL;
  819.     register FILE *fp;
  820.  
  821.     if (tree->rnode) {
  822.         int errflg;    /* not used, sigh */
  823.  
  824.         rp = redirect(tree->rnode, &errflg);
  825.         if (rp != NULL) {
  826.             fp = rp->fp;
  827.             if (fp == NULL)
  828.                 return;
  829.         } else
  830.             return;
  831.     } else
  832.         fp = stdout;
  833.     tree = do_sprintf(tree->lnode);
  834.     efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp, TRUE);
  835.     free_temp(tree);
  836. }
  837.  
  838. /* do_sqrt --- do the sqrt function */
  839.  
  840. NODE *
  841. do_sqrt(tree)
  842. NODE *tree;
  843. {
  844.     NODE *tmp;
  845.     double arg;
  846.  
  847.     tmp = tree_eval(tree->lnode);
  848.     arg = (double) force_number(tmp);
  849.     free_temp(tmp);
  850.     if (arg < 0.0)
  851.         warning("sqrt called with negative argument %g", arg);
  852.     return tmp_number((AWKNUM) sqrt(arg));
  853. }
  854.  
  855. /* do_substr --- do the substr function */
  856.  
  857. NODE *
  858. do_substr(tree)
  859. NODE *tree;
  860. {
  861.     NODE *t1, *t2, *t3;
  862.     NODE *r;
  863.     register int indx;
  864.     size_t length;
  865.     int is_long;
  866.  
  867.     t1 = force_string(tree_eval(tree->lnode));
  868.     t2 = tree_eval(tree->rnode->lnode);
  869.     if (tree->rnode->rnode == NULL)    /* third arg. missing */
  870.         length = t1->stlen;
  871.     else {
  872.         t3 = tree_eval(tree->rnode->rnode->lnode);
  873.         length = (size_t) force_number(t3);
  874.         free_temp(t3);
  875.     }
  876.     indx = (int) force_number(t2) - 1;
  877.     free_temp(t2);
  878.     if (indx < 0)
  879.         indx = 0;
  880.     if (indx >= t1->stlen || (long) length <= 0) {
  881.         if (do_lint && indx >= t1->stlen)
  882.             warning("substr: position %d is past end of string",
  883.                 indx);
  884.         if (do_lint && (long) length <= 0)
  885.             warning("substr: length %d <= 0", (long) length);
  886.         free_temp(t1);
  887.         return Nnull_string;
  888.     }
  889.     if ((is_long = (indx + length > t1->stlen)) || LONG_MAX - indx < length) {
  890.         length = t1->stlen - indx;
  891.         if (do_lint && is_long)
  892.             warning("substr: length %d at position %d exceeds length of first argument",
  893.                 length, indx+1);
  894.     }
  895.     r = tmp_string(t1->stptr + indx, length);
  896.     free_temp(t1);
  897.     return r;
  898. }
  899.  
  900. /* do_strftime --- format a time stamp */
  901.  
  902. NODE *
  903. do_strftime(tree)
  904. NODE *tree;
  905. {
  906.     NODE *t1, *t2, *ret;
  907.     struct tm *tm;
  908.     time_t fclock;
  909.     char buf[BUFSIZ];    /* XXX - fixed length */
  910.     static char def_format[] = "%a %b %d %H:%M:%S %Z %Y";
  911.     char *format;
  912.  
  913.     /* set defaults first */
  914.     format = def_format;    /* traditional date format */
  915.     (void) time(&fclock);    /* current time of day */
  916.  
  917.     t1 = t2 = NULL;
  918.     if (tree != NULL) {    /* have args */
  919.         if (tree->lnode != NULL) {
  920.             t1 = force_string(tree_eval(tree->lnode));
  921.             format = t1->stptr;
  922.             if (do_lint && t1->stlen == 0)
  923.                 warning("strftime called with empty format string");
  924.         }
  925.     
  926.         if (tree->rnode != NULL) {
  927.             t2 = tree_eval(tree->rnode->lnode);
  928.             fclock = (time_t) force_number(t2);
  929.             free_temp(t2);
  930.         }
  931.     }
  932.  
  933.     tm = localtime(&fclock);
  934.  
  935.     ret = tmp_string(buf, strftime(buf, 100, format, tm));
  936.     if (t1)
  937.         free_temp(t1);
  938.     return ret;
  939. }
  940.  
  941. /* do_systime --- get the time of day */
  942.  
  943. NODE *
  944. do_systime(tree)
  945. NODE *tree;
  946. {
  947.     time_t lclock;
  948.  
  949.     (void) time(&lclock);
  950.     return tmp_number((AWKNUM) lclock);
  951. }
  952.  
  953. /* do_system --- run an external command */
  954.  
  955. NODE *
  956. do_system(tree)
  957. NODE *tree;
  958. {
  959.     NODE *tmp;
  960.     int ret = 0;
  961.     char *cmd;
  962.     char save;
  963.  
  964.     (void) flush_io();     /* so output is synchronous with gawk's */
  965.     tmp = tree_eval(tree->lnode);
  966.     cmd = force_string(tmp)->stptr;
  967.  
  968.     if (cmd && *cmd) {
  969.         /* insure arg to system is zero-terminated */
  970.  
  971.         /*
  972.          * From: David Trueman <david@cs.dal.ca>
  973.          * To: arnold@cc.gatech.edu (Arnold Robbins)
  974.          * Date: Wed, 3 Nov 1993 12:49:41 -0400
  975.          * 
  976.          * It may not be necessary to save the character, but
  977.          * I'm not sure.  It would normally be the field
  978.          * separator.  If the parse has not yet gone beyond
  979.          * that, it could mess up (although I doubt it).  If
  980.          * FIELDWIDTHS is being used, it might be the first
  981.          * character of the next field.  Unless someone wants
  982.          * to check it out exhaustively, I suggest saving it
  983.          * for now...
  984.          */
  985.         save = cmd[tmp->stlen];
  986.         cmd[tmp->stlen] = '\0';
  987.  
  988.         ret = system(cmd);
  989.         ret = (ret >> 8) & 0xff;
  990.  
  991.         cmd[tmp->stlen] = save;
  992.     }
  993.     free_temp(tmp);
  994.     return tmp_number((AWKNUM) ret);
  995. }
  996.  
  997. extern NODE **fmt_list;  /* declared in eval.c */
  998.  
  999. /* do_print --- print items, separated by OFS, terminated with ORS */
  1000.  
  1001. void 
  1002. do_print(tree)
  1003. register NODE *tree;
  1004. {
  1005.     register NODE *t1;
  1006.     struct redirect *rp = NULL;
  1007.     register FILE *fp;
  1008.     register char *s;
  1009.  
  1010.     if (tree->rnode) {
  1011.         int errflg;        /* not used, sigh */
  1012.  
  1013.         rp = redirect(tree->rnode, &errflg);
  1014.         if (rp != NULL) {
  1015.             fp = rp->fp;
  1016.             if (fp == NULL)
  1017.                 return;
  1018.         } else
  1019.             return;
  1020.     } else
  1021.         fp = stdout;
  1022.     tree = tree->lnode;
  1023.     while (tree != NULL) {
  1024.         t1 = tree_eval(tree->lnode);
  1025.         if (t1->flags & NUMBER) {
  1026.             if (OFMTidx == CONVFMTidx)
  1027.                 (void) force_string(t1);
  1028.             else {
  1029.                 free_temp(t1);
  1030.                 t1 = format_tree(OFMT,
  1031.                          fmt_list[OFMTidx]->stlen,
  1032.                          tree);
  1033.             }
  1034.         }
  1035.         efwrite(t1->stptr, sizeof(char), t1->stlen, fp, "print", rp, FALSE);
  1036.         free_temp(t1);
  1037.         tree = tree->rnode;
  1038.         if (tree != NULL) {
  1039.             s = OFS;
  1040.             if (OFSlen > 0)
  1041.                 efwrite(s, sizeof(char), (size_t) OFSlen,
  1042.                     fp, "print", rp, FALSE);
  1043.         }
  1044.     }
  1045.     s = ORS;
  1046.     if (ORSlen > 0)
  1047.         efwrite(s, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE);
  1048. }
  1049.  
  1050. /* do_tolower --- lower case a string */
  1051.  
  1052. NODE *
  1053. do_tolower(tree)
  1054. NODE *tree;
  1055. {
  1056.     NODE *t1, *t2;
  1057.     register char *cp, *cp2;
  1058.  
  1059.     t1 = tree_eval(tree->lnode);
  1060.     t1 = force_string(t1);
  1061.     t2 = tmp_string(t1->stptr, t1->stlen);
  1062.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  1063.         if (isupper(*cp))
  1064.             *cp = tolower(*cp);
  1065.     free_temp(t1);
  1066.     return t2;
  1067. }
  1068.  
  1069. /* do_toupper --- upper case a string */
  1070.  
  1071. NODE *
  1072. do_toupper(tree)
  1073. NODE *tree;
  1074. {
  1075.     NODE *t1, *t2;
  1076.     register char *cp;
  1077.  
  1078.     t1 = tree_eval(tree->lnode);
  1079.     t1 = force_string(t1);
  1080.     t2 = tmp_string(t1->stptr, t1->stlen);
  1081.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  1082.         if (islower(*cp))
  1083.             *cp = toupper(*cp);
  1084.     free_temp(t1);
  1085.     return t2;
  1086. }
  1087.  
  1088. /* do_atan2 --- do the atan2 function */
  1089.  
  1090. NODE *
  1091. do_atan2(tree)
  1092. NODE *tree;
  1093. {
  1094.     NODE *t1, *t2;
  1095.     double d1, d2;
  1096.  
  1097.     t1 = tree_eval(tree->lnode);
  1098.     t2 = tree_eval(tree->rnode->lnode);
  1099.     d1 = force_number(t1);
  1100.     d2 = force_number(t2);
  1101.     free_temp(t1);
  1102.     free_temp(t2);
  1103.     return tmp_number((AWKNUM) atan2(d1, d2));
  1104. }
  1105.  
  1106. /* do_sin --- do the sin function */
  1107.  
  1108. NODE *
  1109. do_sin(tree)
  1110. NODE *tree;
  1111. {
  1112.     NODE *tmp;
  1113.     double d;
  1114.  
  1115.     tmp = tree_eval(tree->lnode);
  1116.     d = sin((double) force_number(tmp));
  1117.     free_temp(tmp);
  1118.     return tmp_number((AWKNUM) d);
  1119. }
  1120.  
  1121. /* do_cos --- do the cos function */
  1122.  
  1123. NODE *
  1124. do_cos(tree)
  1125. NODE *tree;
  1126. {
  1127.     NODE *tmp;
  1128.     double d;
  1129.  
  1130.     tmp = tree_eval(tree->lnode);
  1131.     d = cos((double) force_number(tmp));
  1132.     free_temp(tmp);
  1133.     return tmp_number((AWKNUM) d);
  1134. }
  1135.  
  1136. /* do_rand --- do the rand function */
  1137.  
  1138. static int firstrand = TRUE;
  1139. static char state[512];
  1140.  
  1141. /* ARGSUSED */
  1142. NODE *
  1143. do_rand(tree)
  1144. NODE *tree;
  1145. {
  1146.     if (firstrand) {
  1147.         (void) initstate((unsigned) 1, state, sizeof state);
  1148.         srandom(1);
  1149.         firstrand = FALSE;
  1150.     }
  1151.     return tmp_number((AWKNUM) random() / GAWK_RANDOM_MAX);
  1152. }
  1153.  
  1154. /* do_srand --- seed the random number generator */
  1155.  
  1156. NODE *
  1157. do_srand(tree)
  1158. NODE *tree;
  1159. {
  1160.     NODE *tmp;
  1161.     static long save_seed = 1;
  1162.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  1163.  
  1164.     if (firstrand) {
  1165.         (void) initstate((unsigned) 1, state, sizeof state);
  1166.         /* don't need to srandom(1), we're changing the seed below */
  1167.         firstrand = FALSE;
  1168.     } else
  1169.         (void) setstate(state);
  1170.  
  1171.     if (tree == NULL)
  1172.         srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
  1173.     else {
  1174.         tmp = tree_eval(tree->lnode);
  1175.         srandom((unsigned int) (save_seed = (long) force_number(tmp)));
  1176.         free_temp(tmp);
  1177.     }
  1178.     return tmp_number((AWKNUM) ret);
  1179. }
  1180.  
  1181. /* do_match --- match a regexp, set RSTART and RLENGTH */
  1182.  
  1183. NODE *
  1184. do_match(tree)
  1185. NODE *tree;
  1186. {
  1187.     NODE *t1;
  1188.     int rstart;
  1189.     AWKNUM rlength;
  1190.     Regexp *rp;
  1191.  
  1192.     t1 = force_string(tree_eval(tree->lnode));
  1193.     tree = tree->rnode->lnode;
  1194.     rp = re_update(tree);
  1195.     rstart = research(rp, t1->stptr, 0, t1->stlen, TRUE);
  1196.     if (rstart >= 0) {    /* match succeded */
  1197.         rstart++;    /* 1-based indexing */
  1198.         rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr);
  1199.     } else {        /* match failed */
  1200.         rstart = 0;
  1201.         rlength = -1.0;
  1202.     }
  1203.     free_temp(t1);
  1204.     unref(RSTART_node->var_value);
  1205.     RSTART_node->var_value = make_number((AWKNUM) rstart);
  1206.     unref(RLENGTH_node->var_value);
  1207.     RLENGTH_node->var_value = make_number(rlength);
  1208.     return tmp_number((AWKNUM) rstart);
  1209. }
  1210.  
  1211. /* sub_common --- the common code (does the work) for sub, gsub, and gensub */
  1212.  
  1213. /*
  1214.  * NB: `howmany' conflicts with a SunOS macro in <sys/param.h>.
  1215.  */
  1216.  
  1217. static NODE *
  1218. sub_common(tree, how_many, backdigs)
  1219. NODE *tree;
  1220. int how_many, backdigs;
  1221. {
  1222.     register char *scan;
  1223.     register char *bp, *cp;
  1224.     char *buf;
  1225.     size_t buflen;
  1226.     register char *matchend;
  1227.     register size_t len;
  1228.     char *matchstart;
  1229.     char *text;
  1230.     size_t textlen;
  1231.     char *repl;
  1232.     char *replend;
  1233.     size_t repllen;
  1234.     int sofar;
  1235.     int ampersands;
  1236.     int matches = 0;
  1237.     Regexp *rp;
  1238.     NODE *s;        /* subst. pattern */
  1239.     NODE *t;        /* string to make sub. in; $0 if none given */
  1240.     NODE *tmp;
  1241.     NODE **lhs = &tree;    /* value not used -- just different from NULL */
  1242.     int priv = FALSE;
  1243.     Func_ptr after_assign = NULL;
  1244.  
  1245.     int global = (how_many == -1);
  1246.     long current;
  1247.  
  1248.     tmp = tree->lnode;
  1249.     rp = re_update(tmp);
  1250.  
  1251.     tree = tree->rnode;
  1252.     s = tree->lnode;
  1253.  
  1254.     tree = tree->rnode;
  1255.     tmp = tree->lnode;
  1256.     t = force_string(tree_eval(tmp));
  1257.  
  1258.     /* do the search early to avoid work on non-match */
  1259.     if (research(rp, t->stptr, 0, t->stlen, TRUE) == -1 ||
  1260.         RESTART(rp, t->stptr) > t->stlen) {
  1261.         free_temp(t);
  1262.         return tmp_number((AWKNUM) 0.0);
  1263.     }
  1264.  
  1265.     if (tmp->type == Node_val)
  1266.         lhs = NULL;
  1267.     else
  1268.         lhs = get_lhs(tmp, &after_assign);
  1269.     t->flags |= STRING;
  1270.     /*
  1271.      * create a private copy of the string
  1272.      */
  1273.     if (t->stref > 1 || (t->flags & PERM)) {
  1274.         unsigned int saveflags;
  1275.  
  1276.         saveflags = t->flags;
  1277.         t->flags &= ~MALLOC;
  1278.         tmp = dupnode(t);
  1279.         t->flags = saveflags;
  1280.         t = tmp;
  1281.         priv = TRUE;
  1282.     }
  1283.     text = t->stptr;
  1284.     textlen = t->stlen;
  1285.     buflen = textlen + 2;
  1286.  
  1287.     s = force_string(tree_eval(s));
  1288.     repl = s->stptr;
  1289.     replend = repl + s->stlen;
  1290.     repllen = replend - repl;
  1291.     emalloc(buf, char *, buflen + 2, "sub_common");
  1292.     buf[buflen] = '\0';
  1293.     buf[buflen + 1] = '\0';
  1294.     ampersands = 0;
  1295.     for (scan = repl; scan < replend; scan++) {
  1296.         if (*scan == '&') {
  1297.             repllen--;
  1298.             ampersands++;
  1299.         } else if (*scan == '\\') {
  1300.             if (backdigs) {    /* gensub, behave sanely */
  1301.                 if (isdigit(scan[1])) {
  1302.                     ampersands++;
  1303.                     scan++;
  1304.                 } else {    /* \q for any q --> q */
  1305.                     repllen--;
  1306.                     scan++;
  1307.                 }
  1308.             } else {    /* (proposed) posix '96 mode */
  1309.                 if (strncmp(scan, "\\\\\\&", 4) == 0) {
  1310.                     /* \\\& --> \& */
  1311.                     repllen -= 2;
  1312.                     scan += 3;
  1313.                 } else if (strncmp(scan, "\\\\&", 3) == 0) {
  1314.                     /* \\& --> \<string> */
  1315.                     ampersands++;
  1316.                     repllen--;
  1317.                     scan += 2;
  1318.                 } else if (scan[1] == '&') {
  1319.                     /* \& --> & */
  1320.                     repllen--;
  1321.                     scan++;
  1322.                 } /* else
  1323.                     leave alone, it goes into the output */
  1324.             }
  1325.         }
  1326.     }
  1327.  
  1328.     bp = buf;
  1329.     for (current = 1;; current++) {
  1330.         matches++;
  1331.         matchstart = t->stptr + RESTART(rp, t->stptr);
  1332.         matchend = t->stptr + REEND(rp, t->stptr);
  1333.  
  1334.         /*
  1335.          * create the result, copying in parts of the original
  1336.          * string 
  1337.          */
  1338.         len = matchstart - text + repllen
  1339.               + ampersands * (matchend - matchstart);
  1340.         sofar = bp - buf;
  1341.         while (buflen < (sofar + len + 1)) {
  1342.             buflen *= 2;
  1343.             erealloc(buf, char *, buflen, "sub_common");
  1344.             bp = buf + sofar;
  1345.         }
  1346.         for (scan = text; scan < matchstart; scan++)
  1347.             *bp++ = *scan;
  1348.         if (global || current == how_many) {
  1349.             /*
  1350.              * If replacing all occurrences, or this is the
  1351.              * match we want, copy in the replacement text,
  1352.              * making substitutions as we go.
  1353.              */
  1354.             for (scan = repl; scan < replend; scan++)
  1355.                 if (*scan == '&')
  1356.                     for (cp = matchstart; cp < matchend; cp++)
  1357.                         *bp++ = *cp;
  1358.                 else if (*scan == '\\') {
  1359.                     if (backdigs) {    /* gensub, behave sanely */
  1360.                         if (isdigit(scan[1])) {
  1361.                             int dig = scan[1] - '0';
  1362.                             char *start, *end;
  1363.         
  1364.                             start = t->stptr
  1365.                                   + SUBPATSTART(rp, t->stptr, dig);
  1366.                             end = t->stptr
  1367.                                   + SUBPATEND(rp, t->stptr, dig);
  1368.         
  1369.                             for (cp = start; cp < end; cp++)
  1370.                                 *bp++ = *cp;
  1371.                             scan++;
  1372.                         } else    /* \q for any q --> q */
  1373.                             *bp++ = *++scan;
  1374.                     } else {    /* posix '96 mode, bleah */
  1375.                         if (strncmp(scan, "\\\\\\&", 4) == 0) {
  1376.                             /* \\\& --> \& */
  1377.                             *bp++ = '\\';
  1378.                             *bp++ = '&';
  1379.                             scan += 3;
  1380.                         } else if (strncmp(scan, "\\\\&", 3) == 0) {
  1381.                             /* \\& --> \<string> */
  1382.                             *bp++ = '\\';
  1383.                             for (cp = matchstart; cp < matchend; cp++)
  1384.                                 *bp++ = *cp;
  1385.                             scan += 2;
  1386.                         } else if (scan[1] == '&') {
  1387.                             /* \& --> & */
  1388.                             *bp++ = '&';
  1389.                             scan++;
  1390.                         } else
  1391.                             *bp++ = *scan;
  1392.                     }
  1393.                 } else
  1394.                     *bp++ = *scan;
  1395.         } else {
  1396.             /*
  1397.              * don't want this match, skip over it by copying
  1398.              * in current text.
  1399.              */
  1400.             for (cp = matchstart; cp < matchend; cp++)
  1401.                 *bp++ = *cp;
  1402.         }
  1403.         /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */
  1404.         if (matchstart == matchend && matchend < text + textlen) {
  1405.             *bp++ = *matchend;
  1406.             matchend++;
  1407.         }
  1408.         textlen = text + textlen - matchend;
  1409.         text = matchend;
  1410.         if ((current >= how_many && !global) || (long) textlen <= 0
  1411.             || research(rp, t->stptr, text - t->stptr, textlen, TRUE) == -1)
  1412.             break;
  1413.     }
  1414.     sofar = bp - buf;
  1415.     if (buflen - sofar - textlen - 1) {
  1416.         buflen = sofar + textlen + 2;
  1417.         erealloc(buf, char *, buflen, "sub_common");
  1418.         bp = buf + sofar;
  1419.     }
  1420.     for (scan = matchend; scan < text + textlen; scan++)
  1421.         *bp++ = *scan;
  1422.     *bp = '\0';
  1423.     textlen = bp - buf;
  1424.     free(t->stptr);
  1425.     t->stptr = buf;
  1426.     t->stlen = textlen;
  1427.  
  1428.     free_temp(s);
  1429.     if (matches > 0 && lhs) {
  1430.         if (priv) {
  1431.             unref(*lhs);
  1432.             *lhs = t;
  1433.         }
  1434.         if (after_assign != NULL)
  1435.             (*after_assign)();
  1436.         t->flags &= ~(NUM|NUMBER);
  1437.     }
  1438.     return tmp_number((AWKNUM) matches);
  1439. }
  1440.  
  1441. /* do_gsub --- global substitution */
  1442.  
  1443. NODE *
  1444. do_gsub(tree)
  1445. NODE *tree;
  1446. {
  1447.     return sub_common(tree, -1, FALSE);
  1448. }
  1449.  
  1450. /* do_sub --- single substitution */
  1451.  
  1452. NODE *
  1453. do_sub(tree)
  1454. NODE *tree;
  1455. {
  1456.     return sub_common(tree, 1, FALSE);
  1457. }
  1458.  
  1459. /* do_gensub --- fix up the tree for sub_common for the gensub function */
  1460.  
  1461. NODE *
  1462. do_gensub(tree)
  1463. NODE *tree;
  1464. {
  1465.     NODE n1, n2, n3, *t, *tmp, *target, *ret;
  1466.     long how_many = 1;    /* default is one substitution */
  1467.     double d;
  1468.  
  1469.     /*
  1470.      * We have to pull out the value of the global flag, and
  1471.      * build up a tree without the flag in it, turning it into the
  1472.      * kind of tree that sub_common() expects.  It helps to draw
  1473.      * a picture of this ...
  1474.      */
  1475.     n1 = *tree;
  1476.     n2 = *(tree->rnode);
  1477.     n1.rnode = & n2;
  1478.  
  1479.     t = tree_eval(n2.rnode->lnode);    /* value of global flag */
  1480.  
  1481.     tmp = force_string(tree_eval(n2.rnode->rnode->lnode));    /* target */
  1482.  
  1483.     /*
  1484.      * We make copy of the original target string, and pass that
  1485.      * in to sub_common() as the target to make the substitution in.
  1486.      * We will then return the result string as the return value of
  1487.      * this function.
  1488.      */
  1489.     target = tmp_string(tmp->stptr, tmp->stlen);
  1490.     free_temp(tmp);
  1491.  
  1492.     n3 = *(n2.rnode->rnode);
  1493.     n3.lnode = target;
  1494.     n2.rnode = & n3;
  1495.  
  1496.     if ((t->flags & (STR|STRING)) != 0) {
  1497.         if (t->stlen > 0 && (t->stptr[0] == 'g' || t->stptr[0] == 'G'))
  1498.             how_many = -1;
  1499.         else
  1500.             how_many = 1;
  1501.     } else {
  1502.         d = force_number(t);
  1503.         if (d > 0)
  1504.             how_many = d;
  1505.         else
  1506.             how_many = 1;
  1507.     }
  1508.  
  1509.     free_temp(t);
  1510.  
  1511.     ret = sub_common(&n1, how_many, TRUE);
  1512.     free_temp(ret);
  1513.  
  1514.     /*
  1515.      * Note that we don't care what sub_common() returns, since the
  1516.      * easiest thing for the programmer is to return the string, even
  1517.      * if no substitutions were done.
  1518.      */
  1519.     return target;
  1520. }
  1521.  
  1522. #ifdef GFMT_WORKAROUND
  1523. /*
  1524.  * printf's %g format [can't rely on gcvt()]
  1525.  *    caveat: don't use as argument to *printf()!
  1526.  * 'format' string HAS to be of "<flags>*.*g" kind, or we bomb!
  1527.  */
  1528. static void
  1529. sgfmt(buf, format, alt, fwidth, prec, g)
  1530. char *buf;    /* return buffer; assumed big enough to hold result */
  1531. const char *format;
  1532. int alt;    /* use alternate form flag */
  1533. int fwidth;    /* field width in a format */
  1534. int prec;    /* indicates desired significant digits, not decimal places */
  1535. double g;    /* value to format */
  1536. {
  1537.     char dform[40];
  1538.     register char *gpos;
  1539.     register char *d, *e, *p;
  1540.     int again = FALSE;
  1541.  
  1542.     strncpy(dform, format, sizeof dform - 1);
  1543.     dform[sizeof dform - 1] = '\0';
  1544.     gpos = strrchr(dform, '.');
  1545.  
  1546.     if (g == 0.0 && ! alt) {    /* easy special case */
  1547.         *gpos++ = 'd';
  1548.         *gpos = '\0';
  1549.         (void) sprintf(buf, dform, fwidth, 0);
  1550.         return;
  1551.     }
  1552.  
  1553.     /* advance to location of 'g' in the format */
  1554.     while (*gpos && *gpos != 'g' && *gpos != 'G')
  1555.         gpos++;
  1556.  
  1557.     if (prec <= 0)          /* negative precision is ignored */
  1558.         prec = (prec < 0 ?  DEFAULT_G_PRECISION : 1);
  1559.  
  1560.     if (*gpos == 'G')
  1561.         again = TRUE;
  1562.     /* start with 'e' format (it'll provide nice exponent) */
  1563.     *gpos = 'e';
  1564.     prec--;
  1565.     (void) sprintf(buf, dform, fwidth, prec, g);
  1566.     if ((e = strrchr(buf, 'e')) != NULL) {    /* find exponent  */
  1567.         int expn = atoi(e+1);        /* fetch exponent */
  1568.         if (expn >= -4 && expn <= prec) {    /* per K&R2, B1.2 */
  1569.             /* switch to 'f' format and re-do */
  1570.             *gpos = 'f';
  1571.             prec -= expn;        /* decimal precision */
  1572.             (void) sprintf(buf, dform, fwidth, prec, g);
  1573.             e = buf + strlen(buf);
  1574.             while (*--e == ' ')
  1575.                 continue;
  1576.             e++;
  1577.         }
  1578.         else if (again)
  1579.             *gpos = 'E';
  1580.  
  1581.         /* if 'alt' in force, then trailing zeros are not removed */
  1582.         if (! alt && (d = strrchr(buf, '.')) != NULL) {
  1583.             /* throw away an excess of precision */
  1584.             for (p = e; p > d && *--p == '0'; )
  1585.                 prec--;
  1586.             if (d == p)
  1587.                 prec--;
  1588.             if (prec < 0)
  1589.                 prec = 0;
  1590.             /* and do that once again */
  1591.             again = TRUE;
  1592.         }
  1593.         if (again)
  1594.             (void) sprintf(buf, dform, fwidth, prec, g);
  1595.     }
  1596. }
  1597. #endif    /* GFMT_WORKAROUND */
  1598.